package com.ourteam.product.requirement.api;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.squirrelframework.foundation.fsm.StateMachineBuilderFactory;
import org.squirrelframework.foundation.fsm.UntypedStateMachine;
import org.squirrelframework.foundation.fsm.UntypedStateMachineBuilder;

import com.ourteam.frame.controller.AbstractServiceController;
//import com.ourteam.frame.oss.utils.OSSUtils;
import com.ourteam.frame.web.AbstractSearchHelper;
import com.ourteam.frame.web.GridBean;
import com.ourteam.frame.web.OperationResult;
import com.ourteam.product.requirement.dao.IProductIssueChangeLogDAO;
import com.ourteam.product.requirement.dao.IProductIssueDAO;
import com.ourteam.product.requirement.dao.IProductIssueNoteDAO;
import com.ourteam.product.requirement.dao.ProductIssueAttachDAOQueryBean;
import com.ourteam.product.requirement.dao.ProductIssueChangeLogDAOQueryBean;
import com.ourteam.product.requirement.dao.ProductIssueDAOQueryBean;
import com.ourteam.product.requirement.dao.ProductIssueNoteDAOQueryBean;
import com.ourteam.product.requirement.dao.ProductTeamDAOQueryBean;
import com.ourteam.product.requirement.domain.ProductIssueAttachBean;
import com.ourteam.product.requirement.domain.ProductIssueBean;
import com.ourteam.product.requirement.domain.ProductIssueChangeLogBean;
import com.ourteam.product.requirement.domain.ProductIssueNoteBean;
import com.ourteam.product.requirement.domain.ProductTeamBean;
import com.ourteam.product.requirement.service.IProductIssueService;
import com.ourteam.product.requirement.service.IProductService;
import com.ourteam.product.requirement.service.ProductIssueServiceFactory;
import com.ourteam.product.requirement.service.ProductServiceFactory;

@Controller
@RequestMapping("/productIssue")
public class ProductIssueAPI extends AbstractServiceController {

	private static final IProductIssueService PRODUCT_ISSUE_SERVICE = ProductIssueServiceFactory
			.getProductIssueService();

	private static final IProductService PRODUCT_DEFINE_SERVICE = ProductServiceFactory.getProductService();

	protected ProductIssueDAOQueryBean filteData(ProductIssueSearchModel searchModel,
			ProductIssueDAOQueryBean queryBean) throws Exception {

		if (StringUtils.isEmpty(searchModel.getStatus())) {

			ProductIssueDAOQueryBean.Criteria criterion = queryBean.createCriteria();

			criterion.andStatusEqualTo("unsubmitted").andCreatorIdEqualTo(getLoginUserId());

			queryBean.and(criterion);

			ProductIssueDAOQueryBean orQueryBean = new ProductIssueDAOQueryBean();

			searchModel.buildPageQueryBean(orQueryBean);

			ProductIssueDAOQueryBean.Criteria criteriaB = queryBean.createCriteria();

			criteriaB.andStatusNotEqualTo("unsubmitted");

			orQueryBean.and(criteriaB);

			queryBean.union(orQueryBean);
			
			if(queryBean.getSortProperties().isEmpty()) {
				orQueryBean.setSortProperty(IProductIssueDAO.CreateTime, false);
			}
			else {
				orQueryBean.getSortProperties().addAll(queryBean.getSortProperties());
			}
			
		}
		
		if(queryBean.getSortProperties().isEmpty()) {
			queryBean.setSortProperty(IProductIssueDAO.CreateTime, false);
		}

		return queryBean;
	}

	@RequestMapping("/queryProductIssues")
	@ResponseBody
	public GridBean queryProductIssues(@ModelAttribute ProductIssueSearchModel searchModel, HttpServletRequest request,
			Model model) throws Exception {

		AbstractSearchHelper<ProductIssueDAOQueryBean, ProductIssueSearchModel> searchHelper = new AbstractSearchHelper<ProductIssueDAOQueryBean, ProductIssueSearchModel>(
				searchModel) {

			@Override
			protected int queryCount(ProductIssueDAOQueryBean queryBean) throws Exception {
				return PRODUCT_ISSUE_SERVICE.queryProductIssueCount(filteData(searchModel, queryBean));
			}

			@Override
			protected Object[] queryData(ProductIssueDAOQueryBean queryBean) throws Exception {
				return PRODUCT_ISSUE_SERVICE.queryProductIssues(filteData(searchModel, queryBean));
			}

			@Override
			protected ProductIssueDAOQueryBean createQueryBean() {
				return new ProductIssueDAOQueryBean();
			}

		};

		return searchHelper.doSearch(request);

	}

	@RequestMapping("/queryProductIssuesStatistics")
	@ResponseBody
	public Map<String, Object> queryProductIssuesStatistics(@ModelAttribute ProductIssueSearchModel searchModel,
			HttpServletRequest request, Model model) throws Exception {

		ProductIssueDAOQueryBean queryBean = new ProductIssueDAOQueryBean();

		searchModel.buildQueryBean(queryBean);

		ProductIssueDAOQueryBean.Criteria criterion = queryBean.createCriteria();

		criterion.andStatusEqualTo("unsubmitted").andCreatorIdEqualTo(getLoginUserId());

		queryBean.and(criterion);

		Map<String, Object> unsubmitedResult = PRODUCT_ISSUE_SERVICE.queryProductIssuesStatistics(queryBean);

		queryBean.clear();

		searchModel.buildQueryBean(queryBean);

		criterion = queryBean.createCriteria();

		criterion.andStatusNotEqualTo("unsubmitted");

		queryBean.and(criterion);

		Map<String, Object> otherResult = PRODUCT_ISSUE_SERVICE.queryProductIssuesStatistics(queryBean);

		otherResult.putAll(unsubmitedResult);

		return otherResult;
	}

	@RequestMapping("/saveProductIssue")
	@ResponseBody
	public ProductIssueBean saveProductIssue(@ModelAttribute ProductIssueBean productIssueBean,
			HttpServletRequest request, Model model) throws Exception {

		long submitterId = getSubmitterId(request);

		if (productIssueBean.getId() == 0) {

			productIssueBean.setCreateTime(new Date());
			productIssueBean.setCreatorId(submitterId);
			productIssueBean.setStatus("unsubmitted");
			PRODUCT_ISSUE_SERVICE.addNewProductIssue(productIssueBean);
		} else {
			productIssueBean.setLastUpdateTime(new Date());
			productIssueBean.setLastUpdateUserId(submitterId);
			PRODUCT_ISSUE_SERVICE.modifyProductIssue(productIssueBean);
		}

		return productIssueBean;

	}

	@RequestMapping("/deleteProductIssues")
	@ResponseBody
	public OperationResult deleteProductIssues(@RequestParam(name = "ids[]") long[] ids) throws Exception {

		if (ArrayUtils.isEmpty(ids)) {
			return OperationResult.SUCCESS_RESULT;
		}

		PRODUCT_ISSUE_SERVICE.deleteProductIssues(ids);

		return OperationResult.SUCCESS_RESULT;
	}

	@RequestMapping("/addProductIssueAttachs")
	@ResponseBody
	public ProductIssueAttachBean[] addProductIssueAttachs(@RequestParam long productIssueId,
			@RequestParam(name = "filePaths[]") String[] filePaths) throws Exception {

		ProductIssueAttachBean[] attachBeans = new ProductIssueAttachBean[filePaths.length];

		for (int i = 0; i < attachBeans.length; i++) {
			ProductIssueAttachBean attachBean = new ProductIssueAttachBean();
			String newPath = "userRequirement/" + productIssueId + "/" + FilenameUtils.getName(filePaths[i]);
			//OSSUtils.copy(filePaths[i], newPath);
			//OSSUtils.remove(filePaths[i]);
			attachBean.setAttachFilePath(newPath);
			attachBean.setAttachFileName(FilenameUtils.getName(newPath));
			attachBean.setIssueId(productIssueId);
			attachBean.setUploadTime(new Date());
			attachBean.setUploadUserId(getLoginUserId());
			PRODUCT_ISSUE_SERVICE.addNewProductIssueAttach(attachBean);
			attachBeans[i] = attachBean;
		}

		ProductIssueBean issueBean = PRODUCT_ISSUE_SERVICE.getProductIssueById(productIssueId);

		ProductIssueAttachDAOQueryBean queryBean = new ProductIssueAttachDAOQueryBean();

		queryBean.createCriteria().andIssueIdEqualTo(productIssueId);

		issueBean.setIssueAttachCount(PRODUCT_ISSUE_SERVICE.queryProductIssueAttachCount(queryBean));

		PRODUCT_ISSUE_SERVICE.modifyProductIssue(issueBean);

		return attachBeans;

	}

	@RequestMapping("/removeProductIssueAttachs")
	@ResponseBody
	public OperationResult removeProductIssueAttachs(@RequestParam long productIssueId,
			@RequestParam(name = "attachIds[]") long[] attachIds) throws Exception {

		if (ArrayUtils.isNotEmpty(attachIds)) {

			ProductIssueAttachDAOQueryBean queryBean = new ProductIssueAttachDAOQueryBean();

			queryBean.createCriteria().andIssueIdEqualTo(productIssueId).andIdIn(attachIds);

			ProductIssueAttachBean[] attachBeans = PRODUCT_ISSUE_SERVICE.queryProductIssueAttachs(queryBean);

//			for (int i = 0; i < attachBeans.length; i++) {
//				OSSUtils.remove(attachBeans[i].getAttachFilePath());
//			}

			PRODUCT_ISSUE_SERVICE.deleteProductIssueAttachs(attachIds);

			ProductIssueBean issueBean = PRODUCT_ISSUE_SERVICE.getProductIssueById(productIssueId);

			queryBean.clear();

			queryBean.createCriteria().andIssueIdEqualTo(productIssueId);

			issueBean.setIssueAttachCount(PRODUCT_ISSUE_SERVICE.queryProductIssueAttachCount(queryBean));

			PRODUCT_ISSUE_SERVICE.modifyProductIssue(issueBean);

		}

		return OperationResult.SUCCESS_RESULT;
	}

	@RequestMapping("/getProductIssueById")
	@ResponseBody
	public ProductIssueBean getProductIssueById(@RequestParam long id) throws Exception {
		return PRODUCT_ISSUE_SERVICE.getProductIssueById(id);
	}

	@RequestMapping("/getProductIssueAttachs")
	@ResponseBody
	public ProductIssueAttachBean[] getProductIssueAttachs(@RequestParam long productIssueId) throws Exception {

		ProductIssueAttachDAOQueryBean queryBean = new ProductIssueAttachDAOQueryBean();

		queryBean.createCriteria().andIssueIdEqualTo(productIssueId);

		return PRODUCT_ISSUE_SERVICE.queryProductIssueAttachs(queryBean);
	}

	@RequestMapping("/getProductIssueNotes")
	@ResponseBody
	public ProductIssueNoteBean[] getProductIssueNotes(@RequestParam long productIssueId) throws Exception {

		ProductIssueNoteDAOQueryBean queryBean = new ProductIssueNoteDAOQueryBean();

		queryBean.createCriteria().andIssueIdEqualTo(productIssueId);

		return PRODUCT_ISSUE_SERVICE.queryProductIssueNotes(queryBean);
	}

	@RequestMapping("/queryProductIssueNotes")
	@ResponseBody
	public GridBean queryProductIssueNotes(@ModelAttribute ProductIssueNoteSearchModel searchModel,
			HttpServletRequest request, Model model) throws Exception {

		AbstractSearchHelper<ProductIssueNoteDAOQueryBean, ProductIssueNoteSearchModel> searchHelper = new AbstractSearchHelper<ProductIssueNoteDAOQueryBean, ProductIssueNoteSearchModel>(
				searchModel) {

			@Override
			protected int queryCount(ProductIssueNoteDAOQueryBean queryBean) throws Exception {
				return PRODUCT_ISSUE_SERVICE.queryProductIssueNoteCount(queryBean);
			}

			@Override
			protected Object[] queryData(ProductIssueNoteDAOQueryBean queryBean) throws Exception {
				return PRODUCT_ISSUE_SERVICE.queryProductIssueNotes(queryBean);
			}

			@Override
			protected ProductIssueNoteDAOQueryBean createQueryBean() {
				return new ProductIssueNoteDAOQueryBean();
			}

		};

		return searchHelper.doSearch(request);

	}

	@RequestMapping("/addProductIssueNote")
	@ResponseBody
	public ProductIssueNoteBean addProductIssueNote(@ModelAttribute ProductIssueNoteBean productIssueNoteBean)
			throws Exception {

		productIssueNoteBean.setNoteTime(new Date());

		productIssueNoteBean.setNoteUserId(getLoginUserId());

		PRODUCT_ISSUE_SERVICE.addNewProductIssueNote(productIssueNoteBean);

		ProductIssueBean productIssueBean = PRODUCT_ISSUE_SERVICE
				.getProductIssueById(productIssueNoteBean.getIssueId());

		ProductIssueNoteDAOQueryBean queryBean = new ProductIssueNoteDAOQueryBean();

		queryBean.createCriteria().andIssueIdEqualTo(productIssueNoteBean.getIssueId());

		productIssueBean.setIssueNoteCount(PRODUCT_ISSUE_SERVICE.queryProductIssueNoteCount(queryBean));

		PRODUCT_ISSUE_SERVICE.modifyProductIssue(productIssueBean);

		return productIssueNoteBean;
	}

	@RequestMapping("/deleteProductIssueNotes")
	@ResponseBody
	public OperationResult deleteProductIssueNotes(@RequestParam(name = "ids[]") long[] ids) throws Exception {

		ProductIssueNoteDAOQueryBean queryBean = new ProductIssueNoteDAOQueryBean();

		queryBean.createCriteria().andIdIn(ids);

		ProductIssueNoteBean[] noteBeans = PRODUCT_ISSUE_SERVICE.queryProductIssueNotes(queryBean);

		List<Long> issueIds = new ArrayList<Long>();

		for (int i = 0; i < noteBeans.length; i++) {
			ProductIssueNoteBean productIssueNoteBean = noteBeans[i];
			if (issueIds.contains(productIssueNoteBean.getIssueId()) == false) {
				issueIds.add(productIssueNoteBean.getIssueId());
			}
		}

		PRODUCT_ISSUE_SERVICE.deleteProductIssueNotes(ids);

		for (Iterator<Long> iterator = issueIds.iterator(); iterator.hasNext();) {

			Long issueId = iterator.next();

			ProductIssueBean productIssueBean = PRODUCT_ISSUE_SERVICE.getProductIssueById(issueId);

			queryBean.clear();

			queryBean.createCriteria().andIssueIdEqualTo(issueId);

			productIssueBean.setIssueNoteCount(PRODUCT_ISSUE_SERVICE.queryProductIssueNoteCount(queryBean));

			PRODUCT_ISSUE_SERVICE.modifyProductIssue(productIssueBean);
		}

		return OperationResult.SUCCESS_RESULT;

	}

	@RequestMapping("/getLastIssueNoteUsers")
	@ResponseBody
	public ProductIssueNoteBean[] getLastIssueNoteUsers(@RequestParam long productIssueId) throws Exception {

		ProductIssueNoteDAOQueryBean queryBean = new ProductIssueNoteDAOQueryBean();

		queryBean.createCriteria().andIssueIdEqualTo(productIssueId);

		queryBean.setMaxResults(3);

		queryBean.setSortProperty(IProductIssueNoteDAO.NoteTime, false);

		return PRODUCT_ISSUE_SERVICE.queryProductIssueNotes(queryBean);

	}

	@RequestMapping("/getProductIssueStateEvents")
	@ResponseBody
	public Map<String, List<String>> getProductIssueCanChangeToStates(@RequestParam long productIssueId)
			throws Exception {

		Map<String, List<String>> results = new HashMap<String, List<String>>();

		ProductIssueBean issueBean = PRODUCT_ISSUE_SERVICE.getProductIssueById(productIssueId);

		ProductTeamDAOQueryBean queryBean = new ProductTeamDAOQueryBean();

		queryBean.createCriteria().andStafferIdEqualTo(getLoginUserId())
				.andProductDefineIdEqualTo(issueBean.getProductDefineId());

		ProductTeamBean[] teamBeans = PRODUCT_DEFINE_SERVICE.queryProductTeamStaffers(queryBean);

		if (ArrayUtils.isEmpty(teamBeans)) {
			return results;
		}

		UserRequirementStateMachineContext context = new UserRequirementStateMachineContext();

		context.setOperatorId(getLoginUserId());

		context.setOperatorRole(teamBeans[0].getStafferRole());

		context.setProductIssueBean(issueBean);

		UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UserRequirementStateMachine.class);

		UserRequirementState[] allStates = UserRequirementState.values();

		for (int i = 0; i < allStates.length; i++) {

			UntypedStateMachine fsm = builder.newStateMachine(allStates[i]);

			fsm.start(context);

			UserRequirementEvent[] allEvents = UserRequirementEvent.values();

			List<String> events = new ArrayList<>();

			for (int j = 0; j < allEvents.length; j++) {
				if (fsm.canAccept(allEvents[j]) && fsm.test(allEvents[j], context).equals(allStates[i]) == false) {
					events.add(allEvents[j].name());
				}
			}

			results.put(allStates[i].toString(), events);
		}

		return results;
	}

	@RequestMapping("/changeProductIssueState")
	@ResponseBody
	public ProductIssueBean changeProductIssueState(@RequestParam long productIssueId, @RequestParam String event,
			@RequestParam(required=false) String remarks) throws Exception {

		ProductIssueBean productIssue = PRODUCT_ISSUE_SERVICE.getProductIssueById(productIssueId);

		UntypedStateMachineBuilder builder = StateMachineBuilderFactory.create(UserRequirementStateMachine.class);

		UntypedStateMachine fsm = builder.newStateMachine(UserRequirementState.valueOf(productIssue.getStatus()));

		UserRequirementStateMachineContext context = new UserRequirementStateMachineContext();

		ProductTeamDAOQueryBean queryBean = new ProductTeamDAOQueryBean();

		queryBean.createCriteria().andStafferIdEqualTo(getLoginUserId())
				.andProductDefineIdEqualTo(productIssue.getProductDefineId());

		ProductTeamBean[] teamBeans = PRODUCT_DEFINE_SERVICE.queryProductTeamStaffers(queryBean);

		if (ArrayUtils.isNotEmpty(teamBeans)) {
			context.setOperatorRole(teamBeans[0].getStafferRole());

		}

		context.setOperatorId(getLoginUserId());

		context.setProductIssueBean(productIssue);
		
		context.setOperateRemarks(remarks);

		fsm.start(context);

		fsm.fire(UserRequirementEvent.valueOf(event), context);

		productIssue.setStatus(fsm.getCurrentState().toString());

		PRODUCT_ISSUE_SERVICE.modifyProductIssue(productIssue);

		fsm.terminate();

		return productIssue;
	}

	@RequestMapping("/getProductIssueChangeLogs")
	@ResponseBody
	public ProductIssueChangeLogBean[] getProductIssueChangeLogs(@RequestParam long productIssueId) throws Exception {
		
		ProductIssueChangeLogDAOQueryBean queryBean = new ProductIssueChangeLogDAOQueryBean();
		
		queryBean.createCriteria().andProducrIssueIdEqualTo(productIssueId);
		
		queryBean.setSortProperty(IProductIssueChangeLogDAO.OperateTime);
		
		return PRODUCT_ISSUE_SERVICE.queryProductIssueChangeLogs(queryBean);
		
	}
	
}
